package com.ikingtech.framework.sdk.cmd.cmder;

import com.ikingtech.framework.sdk.utils.Tools;

import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
public class Docker extends AbstractCmder {

    private final String prompt = "docker";

    protected final List<String> commands = Tools.Coll.newList(this.prompt);

    public void execute() {
        this.execute(this.commands);
    }

    public static Build build() {
        Build build = new Build();
        build.commands.addAll(Tools.Coll.newList("build", "-q", "-t"));
        return build;
    }

    public static Pull pull() {
        Pull pull = new Pull();
        pull.commands.add("pull");
        return pull;
    }

    public static Run run() {
        Run run = new Run();
        run.commands.addAll(Tools.Coll.newList("run", "-d", "--privileged=true", "--restart=always"));
        return run;
    }

    public static Start start() {
        Start start = new Start();
        start.commands.add("start");
        return start;
    }

    public static Stop stop() {
        Stop stop = new Stop();
        stop.commands.add("Stop");
        return stop;
    }

    public static Rm rm() {
        Rm rm = new Rm();
        rm.commands.add("rm");
        return rm;
    }

    public static class Build extends Docker {

        public Build dockerFilePath(String dockerFilePath) {
            this.commands.add(dockerFilePath);
            return this;
        }

        public Build imageName(String imageName) {
            this.commands.add(imageName);
            return this;
        }
    }

    public static class Pull extends Docker {

        public Pull imageName(String imageName) {
            this.commands.add(imageName);
            return this;
        }
    }

    public static class Run extends Docker {

        private static final String PARAM_MAP_FORMAT = "{}:{}";

        public Run net(String net) {
            this.commands.add("--net=" + net);
            return this;
        }

        public Run hostname(String hostname) {
            this.commands.add("--hostname=" + hostname);
            return this;
        }

        public Run ports(Map<String, String> ports) {
            ports.forEach((external, internal) -> this.commands.addAll(Tools.Coll.newList("-p", Tools.Str.format(PARAM_MAP_FORMAT, external, internal))));
            return this;
        }

        public Run name(String name) {
            this.commands.addAll(Tools.Coll.newList("--name", name));
            return this;
        }

        public Run root() {
            return this.userGroup(Tools.Coll.newMap(Tools.Coll.Kv.of("root", "root")));
        }

        public Run userGroup(Map<String, String> userGroup) {
            userGroup.forEach((user, group) -> this.commands.addAll(Tools.Coll.newList("--user", Tools.Str.format(PARAM_MAP_FORMAT, user, group))));
            return this;
        }

        public Run volumes(Map<String, String> volumes) {
            volumes.forEach((external, internal) -> this.commands.addAll(Tools.Coll.newList("-v", Tools.Str.format(PARAM_MAP_FORMAT, external, internal))));
            return this;
        }

        public Run env(Map<String, String> env) {
            env.forEach((key, val) -> this.commands.addAll(Tools.Coll.newList("-e", Tools.Str.format("{}={}", key, val))));
            return this;
        }

        public Run imageName(String imageName) {
            this.commands.add(imageName);
            return this;
        }

        public Run options(List<String> options) {
            this.commands.addAll(options);
            return this;
        }
    }

    public static class Start extends Docker {

        public Start containerName(String containerName) {
            this.commands.add(containerName);
            return this;
        }
    }

    public static class Stop extends Docker {

        public Stop containerName(String containerName) {
            this.commands.add(containerName);
            return this;
        }
    }

    public static class Rm extends Docker {

        public Rm containerName(String containerName) {
            this.commands.add(containerName);
            return this;
        }
    }
}
